package com.zdd.ehe.filter;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zdd.ehe.result.Result;
import com.zdd.ehe.util.JwtToken;
import com.zdd.ehe.util.JwtUtil;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExpiredCredentialsException;
import org.apache.shiro.web.filter.authc.AuthenticatingFilter;
import org.apache.shiro.web.filter.authc.FormAuthenticationFilter;
import org.springframework.stereotype.Component;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @title:AccountFilter
 * @author:ZhuiZhu
 * @description:自定义过滤器
 * @createDate: 2023/3/14  21:25
 */
@Component
@Slf4j
public class AccountFilter extends FormAuthenticationFilter{
    /**
     * 根据请求信息生成token，并在 executeLogin（）方法中将该token提交给realm
     * @param servletRequest
     * @param servletResponse
     * @return
     */
    @Override
    protected AuthenticationToken createToken(ServletRequest servletRequest, ServletResponse servletResponse) {
        //获取请求token
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String jwt = request.getHeader("token");

        //System.out.println("createToken :" + jwt);
        if (StringUtils.isEmpty(jwt)){
            return null;
        }
        return new JwtToken(jwt);
    }

    /**
     * 放行OPTIONS请求
     * @param request
     * @param response
     * @param mappedValue
     * @return
     */
    @Override
    protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) {
        if (request instanceof HttpServletRequest) {
            if (((HttpServletRequest) request).getMethod().toUpperCase().equals("OPTIONS")) {
                System.out.println("OPTIONS请求通过");
                return true;
            }
        }
        return super.isAccessAllowed(request, response, mappedValue);
    }

    /**
     * 表示是否拒绝访问，如果为true，则拒绝访问
     * @param servletRequest
     * @param servletResponse
     * @return
     * @throws Exception
     */
    @Override
    protected boolean onAccessDenied(ServletRequest servletRequest, ServletResponse servletResponse) throws Exception {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        String jwt = request.getHeader("token");
        log.debug(request.getRequestURI() + "进入过滤器");
        System.out.println(request.getRequestURI() + "进入过滤器");
        //System.out.println(jwt);

        if (StringUtils.isEmpty(jwt)){
            log.debug("token缺失");
            //System.out.println("token缺失");
//            如果没有jwt，则不需要进行登录处理，只需要进行拦截
            return true;
        } else {
            //要进行jwt校验，
            JwtUtil jwtUtil = new JwtUtil();
            Claims claimByToken = jwtUtil.parseToken(jwt);
            if (claimByToken == null || jwtUtil.isTokenExpired(claimByToken.getExpiration())){
                log.debug("token已失效，请重新登录");
                //System.out.println("token已失效，请重新登录");
                throw new ExpiredCredentialsException("token已失效，请重新登录");
            }
            log.debug(request.getRequestURI() + "通过过滤器");
            System.out.println(request.getRequestURI() + "通过过滤器");
            //执行登录，相当于subject.login(token)
            //return executeLogin(servletRequest,servletResponse);
            return false;
        }
    }

    /**
     * 登录失败
     * @param token
     * @param e
     * @param request
     * @param response
     * @return
     */
    @Override
    protected boolean onLoginFailure(AuthenticationToken token, AuthenticationException e, ServletRequest request, ServletResponse response) {
        HttpServletResponse httpServletResponse = (HttpServletResponse) response;
        Throwable throwable = e.getCause()==null?e:e.getCause();

        String json = JSON.toJSONString(Result.error(throwable.getMessage()));

        try {
//            将错误数据返回给前端
            httpServletResponse.getWriter().print(json);
        } catch (IOException e1) {
            e1.printStackTrace();
        }
        return false;
    }


}
